
// 线程池不建议用 Executors 去创建 , 而是通过 ThreadPoolExecutor的方式，这样可以节约资源。
//Executors返回的线程池对象的弊端如下：
// 1) FixedThreadPool 和 SingleThreadPool :
//        允许的请求队列长度为 Integer.MAX_VALUE , 可能回堆积大量的请求，从而导致 OOM。
// 2）CachedThreadPool 和 ScheduledThreadPool :
//        允许创建的线程数量为 Integer.MAX_VALUE , 可能回堆积大量的请求，从而导致 OOM。
// OOM，全称“Out Of Memory”，当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时，
//                      就会抛出这个error（注：非exception，因为这个问题已经严重到不足以被应用处理）。

import java.util.concurrent.*;
//四种拒绝策略：
//   1）  AbortPolicy (default)  :  最大承载 : 阻塞队列容量 + 最大核心线程池大小  超过这个值时，会抛出异常 -- RejectedExecutionException
//   2）  CallerRunsPolicy  :    最大承载 : 阻塞队列容量 + 最大核心线程池大小  超过这个值时， 其余的任务由main()线程执行
//   3）  DiscardOldestPolicy  :   最大承载 : 阻塞队列容量 + 最大核心线程池大小  超过这个值时，不会抛出异常，也不会执行其余的任务(队列满了，就丢掉任务，不抛出异常)
//   4）  DiscardPolicy  :     最大承载 : 阻塞队列容量 + 最大核心线程池大小  超过这个值时，不会抛出异常，其余任务会尝试和最早执行的线程竞争，如果最早的进程没有结束，则丢掉任务

// 最大线程到底该如何定义？
//    1. CPU 密集型 : 计算机为几核CPU, 最大核心线程池大小就定义为几,可以保持 CPU的效率最高
//                   获取计算机核数 : Runtime.getRuntime().availableProcessors() 。
//    2. IO 密集型 : 判断程序中十分耗IO的线程的数量 , 最大核心线程池大小定义为这个数量的两倍

public class ThreadPoolExecutorDemo {

    public static void main(String[] args) {

        System.out.println(Runtime.getRuntime().availableProcessors());
        //自定义线程池
       ExecutorService threadPoolExecutor = new ThreadPoolExecutor(
                2,    // 核心线程池大小
               Runtime.getRuntime().availableProcessors(),   // 最大核心线程池大小
                3,               // 超过这个时间没有人调用就会释放
                TimeUnit.SECONDS,   // 超时单位
                new LinkedBlockingDeque<>(3),   //阻塞队列  当超过最大长度3时，正在使用的线程池大小会增加
               Executors.defaultThreadFactory(),        //线程工厂，创建线程的，直接用默认值
               new ThreadPoolExecutor.DiscardPolicy()  //拒绝策略,有四种

        );
            try{
                for (int i = 1; i <= 100; i++){
                    threadPoolExecutor.execute(new Thread(() -> {
                        System.out.println(Thread.currentThread().getName() + " : ok...");
                    }));
                }

            }catch(Exception e){
                e.printStackTrace();
            }finally{
                //程序结束，关闭线程池
                threadPoolExecutor.shutdown();
            }
        }
    }

